package com.sensetime.test.annotation;

import com.sensetime.jv.annotation.RequirePermission;
import com.sensetime.jv.feign.AuthFeignService;
import com.sensetime.jv.service.WhiteUrlCacheService;
import com.sensetime.jv.util.JsonUtils;
import com.sensetime.jv.vo.request.ManualPermissionRequestVO;
import com.sensetime.jv.vo.request.WhiteUrlRequestVO;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class PermissionScannerRunner {

    private final RequestMappingHandlerMapping handlerMapping;
    private final AuthFeignService authFeignService;
    private final WhiteUrlCacheService whiteUrlCacheService;

    @Value("${server.servlet.context-path}")
    private String servletPath;

    public PermissionScannerRunner(AuthFeignService authFeignService,
                                   @Qualifier("requestMappingHandlerMapping") RequestMappingHandlerMapping handlerMapping,
                                   WhiteUrlCacheService whiteUrlCacheService) {
        this.authFeignService = authFeignService;
        this.handlerMapping = handlerMapping;
        this.whiteUrlCacheService = whiteUrlCacheService;
    }

    @PostConstruct
    public void run() {
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
        List<ManualPermissionRequestVO> permissionList = new ArrayList<>();
        List<ManualPermissionRequestVO> whiteUrlList   = new ArrayList<>();

        handlerMethods.forEach((info, method) -> {
            RequirePermission rp = AnnotationUtils.findAnnotation(method.getMethod(), RequirePermission.class);

            Set<String> urls    = info.getPathPatternsCondition().getPatternValues();
            Set<String> methods = info.getMethodsCondition().getMethods().isEmpty()
                    ? Set.of(HttpMethod.GET.name())
                    : info.getMethodsCondition().getMethods()
                    .stream()
                    .map(Enum::name)
                    .collect(Collectors.toSet());

            for (String url : urls) {
                for (String httpMethod : methods) {
                    ManualPermissionRequestVO vo = new ManualPermissionRequestVO();
                    vo.setUrl(url);
                    vo.setMethod(httpMethod);
                    vo.setServletPath(servletPath);
                    vo.setDescription(rp == null ? null : rp.description());

                    if (rp == null || rp.whiteUrl()) {
                        whiteUrlList.add(vo);
                    } else {
                        permissionList.add(vo);
                    }
                }
            }
        });

        // 同步白名单
        if (!whiteUrlList.isEmpty()) {
            List<WhiteUrlRequestVO> whiteUrls = whiteUrlList.stream()
                    .map(item -> JsonUtils.objectMapper.convertValue(item, WhiteUrlRequestVO.class))
                    .collect(Collectors.toList());
            whiteUrlCacheService.cacheWhiteUrls(whiteUrls);
        }

        // 同步权限
        if (!permissionList.isEmpty()) {
            authFeignService.syncPermissions(permissionList);
        }
    }
}